'''
MainWindow Class - 图书管理系统图形界面实现

类的职责：
1. 创建并管理图形用户界面
2. 处理用户交互事件
3. 通过 Library 类管理图书数据
4. 提供图书管理的所有操作界面

主要组件：
1. 图书列表显示区域（Treeview）：显示所有图书信息
2. 操作按钮区域：提供添加、删除、修改、借阅、归还功能

类的属性：
- root: tk.Tk                // 主窗口对象
- library: Library           // 图书馆对象，管理所有图书数据
- tree_view: ttk.Treeview   // 显示图书列表的表格组件

主要方法：
- createWidgets()           // 创建所有GUI组件
- loadBooksToTreeView()     // 将图书数据加载到表格中
- onAddBook()              // 处理添加图书事件
- onRemoveBook()           // 处理删除图书事件
- onUpdateBookInfo()       // 处理修改图书信息事件
- onRendBook()             // 处理借阅图书事件
- onReturnBook()           // 处理归还图书事件

子窗口类：
- addBookWindow           // 添加图书窗口，提供图书信息输入界面
- removeWindow           // 删除图书窗口，确认删除操作
- updateInfoWindow       // 更新图书信息窗口，修改图书属性
- rendWindow            // 借阅图书窗口，处理借阅操作
- returnWindow          // 归还图书窗口，处理归还操作

界面设计特点：
1. 使用 ttk 主题组件，支持现代化的界面风格
2. 所有弹出窗口都是模态的，确保操作的完整性
3. 使用统一的字体和尺寸设置，保持界面风格一致
4. 支持窗口缩放，最小尺寸限制在 1600x900
5. 表格支持滚动条，适应大量数据显示
6. 所有输入都有合法性验证

异常处理：
1. 输入验证：检查必填字段、数字格式等
2. 业务逻辑：处理图书已存在、已借出等情况
3. 用户提示：使用消息框显示操作结果和错误信息

使用说明：
1. 主界面显示所有图书信息，可以直接查看图书状态
2. 选择要操作的图书后点击相应按钮进行操作
3. 所有操作都有确认和错误提示，避免误操作
4. 界面字体和布局已优化，适合长时间使用
'''
import tkinter as tk
from tkinter import ttk, messagebox, font
import tkinter.font as tkFont


from book import Book
from library import Library

class mainWindow():

    def __init__(self,root: tk.Tk):

        self.root = root
        self.root.title("图书管理系统")
        self.root.geometry("1600x900") 
        self.root.minsize(1600,1050)

        self.library = Library()

        font_family = "WenQuanYi Micro Hei"  # 或者 "Noto Sans CJK SC"
        
        # 定义一套协调、专业的字体大小，方便统一修改
        font_size_data = 14          # 表格数据行
        font_size_header = 16        # 表格头
        font_size_button = 14        # 按钮
        font_size_frame_title = 13   # “操作区”等标题

        # --- 创建样式 ---
        style = ttk.Style()
        style.configure("Treeview", 
                        font=(font_family, font_size_data),
                        rowheight=int(font_size_data * 4)) # 行高根据字体大小动态计算
        style.configure("Treeview.Heading", 
                        font=(font_family, font_size_header, 'bold'))
        style.configure("TButton", font=(font_family, font_size_button))
        style.configure("TLabelframe.Label", font=(font_family, font_size_frame_title))

        #创建所有的控件
        self.createWidgets()            
        return 
    
    def createWidgets(self):

        main_frame = ttk.Frame(self.root,padding = "10")
        main_frame.pack(fill = tk.BOTH,expand = True)

        # 查询图书Frame
        query_frame = ttk.LabelFrame(main_frame,text = "图书查询",padding = "10")
        query_frame.pack(fill = tk.X,pady = 5)
        # 图书列表Frame
        list_frame = ttk.LabelFrame(main_frame,text = "图书列表",padding = "10")
        list_frame.pack(fill = tk.BOTH,expand = True,pady = 5)

        # ------------------query_frame的控件--------------------
        # 表单项
        ttk.Label(query_frame, text="书名:").grid(row=0, column=0, padx=5, pady=8, sticky="w")
        self.query_name_entry = ttk.Entry(query_frame)
        self.query_name_entry.grid(row=0, column=1, padx=5, pady=8, sticky="ew")

        ttk.Label(query_frame, text="作者:").grid(row=0, column=2, padx=5, pady=8, sticky="w")
        self.query_author_entry = ttk.Entry(query_frame)
        self.query_author_entry.grid(row=0, column=3, padx=5, pady=8, sticky="ew")

        query_btn = tk.Button(query_frame,text = "查询",command = self.onQueryBook)
        query_btn.grid(row = 0,column = 4,padx = 15, pady=5)

        clear_btn = tk.Button(query_frame,text = "清空",command = self.onClear)
        clear_btn.grid(row = 0,column = 5,padx = 15, pady=5)

        query_frame.columnconfigure(1, weight=1)
        query_frame.columnconfigure(3, weight=1)


        # ------------------query_frame的控件--------------------


        # 定义表格
        columns = ("id", "name", "author", "publisher", "status")
        self.tree_view = ttk.Treeview(list_frame, columns=columns, show='headings')

        self.tree_view.heading("id", text="ID")
        self.tree_view.heading("name", text="书名")
        self.tree_view.heading("author", text="作者")
        self.tree_view.heading("publisher", text="出版社")
        self.tree_view.heading("status", text="状态")

        # 设置宽度和对齐方式
        self.tree_view.column("id",width = 100,anchor = tk.CENTER)
        self.tree_view.column("name", width=400)
        self.tree_view.column("author", width=250)
        self.tree_view.column("publisher", width=350)
        self.tree_view.column("status", width=120, anchor=tk.CENTER)

        # 创建一个滚动条
        scrollbar = ttk.Scrollbar(list_frame, orient=tk.VERTICAL, command=self.tree_view.yview)
        self.tree_view.configure(yscroll=scrollbar.set)

        # 布局表格和滚动条
        self.tree_view.pack(side = tk.LEFT,fill = tk.BOTH,expand = True)
        scrollbar.pack(side = tk.RIGHT,fill = tk.Y)
        
        # 创建按钮框架
        action_frame = ttk.LabelFrame(main_frame,text = "操作区",padding = "10")
        action_frame.pack(fill = tk.X,pady = 10)
        # 添加图书按钮
        add_btn = ttk.Button(action_frame,text = "添加图书",command = self.onAddBook)
        add_btn.pack(side = tk.LEFT,padx = 10, pady=10)
        # 删除图书按钮
        remove_btn = ttk.Button(action_frame,text = "删除图书",command = self.onRemoveBook)
        remove_btn.pack(side = tk.LEFT,padx = 10, pady=10)
        # 修改图书按钮
        update_btn = ttk.Button(action_frame, text="修改信息", command=self.onUpdateBookInfo)
        update_btn.pack(side=tk.LEFT, padx=10, pady=10)
        # 借阅图书按钮
        rent_btn = ttk.Button(action_frame, text="借阅图书", command=self.onRendBook)
        rent_btn.pack(side=tk.LEFT, padx=30, pady=10)
        # 归还图书按钮
        return_btn = ttk.Button(action_frame, text="归还图书", command=self.onReturnBook)
        return_btn.pack(side=tk.LEFT, padx=10, pady=10)


        self.loadBooksToTreeView()  
        print("界面框架创建完毕！")
        return 
    
    def loadBooksToTreeView(self):
        """
        从 self.library 获取图书数据，并加载到表格中显示。
        """

        for book in self.tree_view.get_children():
            self.tree_view.delete(book)

        for book in self.library.getAllBooks():
            status = "已借出" if book.isRented_ else "在馆"
            self.tree_view.insert("", tk.END, values=(book.ID_, book.name_, book.author_, book.publisher_, status))

        return 
    
    def onAddBook(self):
        """
        当“添加图书”按钮被点击时，执行此函数。
        """
        print("添加图书按钮被点击！")
        
        add_window = addBookWindow(self)
    
        return 

    def onRemoveBook(self):
        """
        当“删除图书”按钮被点击时，执行此函数。
        """
        # TODO 5: 实现删除选中图书的逻辑
        print("删除图书按钮被点击！")
        remove_window = removeWindow(self)

        pass

    def onUpdateBookInfo(self):

        print("修改信息按钮被点击")

        selected_book = None
        selected_items = self.tree_view.selection()

        if selected_items:
            first_selected_item_id = selected_items[0]
            item_values = self.tree_view.item(first_selected_item_id, "values")
            book_id_str = item_values[0]
            selected_book = self.library.books_.get(int(book_id_str)) 

        update_info_window = updateInfoWindow(self,selected_book)

        return 

    def onRendBook(self):
        print("借阅图书按钮被点击")

        rend_book = rendWindow(self)

        return 

    def onReturnBook(self):
        print("点击归还图书")

        return_book_window = returnWindow(self)
        
        return 

    def onQueryBook(self):
        # 没有任何输入
        if not self.query_author_entry.get() and not self.query_name_entry.get():
            self.loadBooksToTreeView()
            return 
        
        books = []

        # 清空书为查询做准备
        for book in self.tree_view.get_children():
            self.tree_view.delete(book)

        if self.query_author_entry.get() and self.query_name_entry.get():
            # 混合查询
            books = self.library.queryByNameAndAuthor(self.query_name_entry.get(),self.query_author_entry.get())     

        elif self.query_author_entry.get():
            # 通过作者查找
            books = self.library.queryBookByAuthor(self.query_author_entry.get())

        else:
            # 通过书名模糊查找
            books = self.library.queryBookByName(self.query_name_entry.get())

        # 显示查询结果
        for book in books:
                status = "已借出" if book.isRented_ else "在馆"
                self.tree_view.insert("",tk.END,values = (book.ID_, book.name_, book.author_, book.publisher_, status))

        if not books:
            messagebox.showinfo("查询提示",message = "未找到符合的书籍")
            self.loadBooksToTreeView()
            
        return 

    def onClear(self):
        self.query_author_entry.delete(0,tk.END)
        self.query_name_entry.delete(0,tk.END)
        self.loadBooksToTreeView()
        return 

class addBookWindow(tk.Toplevel):


    def __init__(self,parent: mainWindow):
        super().__init__(parent.root)
        self.title("添加图书")
        self.geometry("600x400")
        
        self.parent = parent
        self.transient(parent.root)
        self.grab_set()         # 使对话框为模态窗口
        
        frame = ttk.Frame(self,padding = "10")
        frame.pack(fill = tk.BOTH,expand = True)

        # 表单项
        ttk.Label(frame, text="ID:").grid(row=0, column=0, padx=5, pady=8, sticky="w")
        self.id_entry = ttk.Entry(frame)
        self.id_entry.grid(row=0, column=1, padx=5, pady=8, sticky="ew")

        ttk.Label(frame, text="书名:").grid(row=1, column=0, padx=5, pady=8, sticky="w")
        self.name_entry = ttk.Entry(frame)
        self.name_entry.grid(row=1, column=1, padx=5, pady=8, sticky="ew")

        ttk.Label(frame, text="作者:").grid(row=2, column=0, padx=5, pady=8, sticky="w")
        self.author_entry = ttk.Entry(frame)
        self.author_entry.grid(row=2, column=1, padx=5, pady=8, sticky="ew")

        ttk.Label(frame, text="出版社:").grid(row=3, column=0, padx=5, pady=8, sticky="w")
        self.publisher_entry = ttk.Entry(frame)
        self.publisher_entry.grid(row=3, column=1, padx=5, pady=8, sticky="ew")
        
        # 确保输入框可以随窗口拉伸
        frame.columnconfigure(1, weight=1)

        # -- 操作按钮 --
        button_frame = ttk.Frame(frame)
        button_frame.grid(row=4, column=0, columnspan=2, pady=15)
        
        ttk.Button(button_frame, text="保存", command=self.onSave).pack(side=tk.LEFT, padx=10)
        ttk.Button(button_frame, text="取消", command=self.destroy).pack(side=tk.LEFT, padx=10)

        return
    
    def onSave(self):

        try:
            id_ = int(self.id_entry.get())
        except ValueError:
            messagebox.showerror("错误", "ID必须是整数！",parent=self)
            return

        name_ = self.name_entry.get()
        author_ = self.author_entry.get()
        publisher_ = self.publisher_entry.get()

        if not all ([name_,author_,publisher_]):
            messagebox.showerror("错误", "请填写所有字段！",parent=self)
            return
        
        new_book = Book(id_,name_,author_,publisher_)
        success = self.parent.library.addBook(new_book)

        if success:
            messagebox.showinfo("成功", "新图书添加成功！", parent=self)

            self.parent.loadBooksToTreeView()
            self.destroy()
        else:
            messagebox.showerror("添加失败", f"ID为 {id_} 的图书已存在！", parent=self)

        return 

class removeWindow(tk.Toplevel):


    def __init__(self,parent: mainWindow):
        super().__init__(parent.root)
        self.parent = parent

        self.title("删除图书")
        self.geometry("600x200")
        self.transient(parent.root)
        self.grab_set()

        frame = ttk.Frame(self,padding = "10")
        frame.pack(fill = tk.BOTH,expand = True)

        # 表单项
        ttk.Label(frame, text="ID:").grid(row=0, column=0, padx=5, pady=8, sticky="w")
        self.id_entry = ttk.Entry(frame)
        self.id_entry.grid(row=0, column=1, padx=5, pady=8, sticky="ew")

        if self.parent.tree_view.selection():
            self.id_entry.insert(0, int(self.parent.tree_view.item(self.parent.tree_view.selection()[0],"values")[0]))
       

        # 确保输入框可以随窗口拉伸
        frame.columnconfigure(1, weight=1)

        button_frame = ttk.Frame(frame)
        button_frame.grid(row = 1,column = 0,columnspan = 2,pady = 15)

        ttk.Button(button_frame,text = "删除",command = self.onRemove).pack(side = tk.LEFT, padx = 10)
        ttk.Button(button_frame, text="取消", command=self.destroy).pack(side=tk.LEFT, padx=10)

        return 

    def onRemove(self):
        

        try:
            id_ = int(self.id_entry.get())
        except ValueError:
            messagebox.showerror("错误", "ID必须是整数！",parent=self)
            return

        success = self.parent.library.removeBook(id_)

        if success == True:
            messagebox.showinfo("成功","删除图书成功! ",parent = self)

            self.parent.loadBooksToTreeView()
            self.destroy()
        else:
            messagebox.showerror("删除失败",f"ID为{id_}的图书不存在或者已被借走",parent = self)

        return 
    
class updateInfoWindow(tk.Toplevel):

    def __init__(self,parent: mainWindow,selected_book: Book):
        super().__init__(parent.root)
        self.parent = parent

        self.title("修改图书信息")
        self.geometry("600x400")
        self.transient(parent.root)
        self.grab_set()

        frame = ttk.Frame(self,padding = "10")
        frame.pack(fill = tk.BOTH,expand = True)

        # 表单项
        ttk.Label(frame, text="ID:").grid(row=0, column=0, padx=5, pady=8, sticky="w")
        self.id_entry = ttk.Entry(frame)
        self.id_entry.grid(row=0, column=1, padx=5, pady=8, sticky="ew")

        self.id_entry.bind("<FocusOut>", self.preonIDFocusOut)
        self.id_entry.bind("<Return>", self.preonIDFocusOut) # 按回车也触发

        ttk.Label(frame, text="书名:").grid(row=1, column=0, padx=5, pady=8, sticky="w")
        self.name_entry = ttk.Entry(frame)
        self.name_entry.grid(row=1, column=1, padx=5, pady=8, sticky="ew")

        ttk.Label(frame, text="作者:").grid(row=2, column=0, padx=5, pady=8, sticky="w")
        self.author_entry = ttk.Entry(frame)
        self.author_entry.grid(row=2, column=1, padx=5, pady=8, sticky="ew")

        ttk.Label(frame, text="出版社:").grid(row=3, column=0, padx=5, pady=8, sticky="w")
        self.publisher_entry = ttk.Entry(frame)
        self.publisher_entry.grid(row=3, column=1, padx=5, pady=8, sticky="ew")

        
        # 确保输入框可以随窗口拉伸
        frame.columnconfigure(1, weight=1)

        button_frame = ttk.Frame(frame)
        button_frame.grid(row = 4,column = 0,columnspan = 2,pady = 20)

        self.update_button = ttk.Button(button_frame, text="保存修改", command=self.updateInfo)
        self.update_button.pack(side=tk.LEFT, padx=10)
        ttk.Button(button_frame, text="取消", command=self.destroy).pack(side=tk.LEFT, padx=10)

        # 初始化窗口
        if selected_book:
            self.fillFormWithBookData(selected_book)
        else:
            self.clearAndDisableForm(False)

        return 


    def preonIDFocusOut(self,event):        
        # 加入此函数解决竞争问题    
        self.after(100,self.onIDFocusOut)

        return 

    def onIDFocusOut(self):
        try:
            id_ = int(self.id_entry.get())
            book = self.parent.library.books_.get(id_)
            if book:
                self.fillFormWithBookData(book)
            else:
                self.clearAndDisableForm(id_not_found=True)
        except (ValueError, TypeError):
            self.clearAndDisableForm(False)

        return 

    def fillFormWithBookData(self,book: Book):
        self.id_entry.config(state="normal")
        self.name_entry.config(state="normal")
        self.author_entry.config(state="normal")
        self.publisher_entry.config(state="normal")
        self.update_button.config(state="normal")

        self.id_entry.delete(0,tk.END)
        self.name_entry.delete(0, tk.END)
        self.author_entry.delete(0, tk.END)
        self.publisher_entry.delete(0, tk.END)

        self.id_entry.insert(0, str(book.ID_))
        self.name_entry.insert(0, book.name_)
        self.author_entry.insert(0, book.author_)
        self.publisher_entry.insert(0, book.publisher_)

        return 
    
    def clearAndDisableForm(self,id_not_found: bool):

        self.name_entry.delete(0, tk.END)
        self.author_entry.delete(0, tk.END)
        self.publisher_entry.delete(0, tk.END)

        self.name_entry.config(state="disabled")
        self.author_entry.config(state="disabled")
        self.publisher_entry.config(state="disabled")
        self.update_button.config(state="disabled")
        
        if id_not_found:
            messagebox.showwarning("提示", "未找到该ID对应的图书。", parent=self)

        return 

    def updateInfo(self):
        try:
            id_ = int(self.id_entry.get())
            name = self.name_entry.get()
            author = self.author_entry.get()
            publisher = self.publisher_entry.get()

            if not all([name, author, publisher]):
                messagebox.showerror("输入错误", "书名、作者、出版社均不能为空！", parent=self)
                return

            success = self.parent.library.updateBookInfo(id_, name, author, publisher)
            if success:
                messagebox.showinfo("成功", "图书信息更新成功！", parent=self)

                self.parent.loadBooksToTreeView()
                self.destroy()
            else:
                # 理论上，因为我们有动态检查，这个分支很难进入
                messagebox.showerror("失败", "更新失败，该ID不存在。", parent=self)
        except ValueError:
            messagebox.showerror("输入错误", "ID必须是纯数字！", parent=self)


        return 

class rendWindow(tk.Toplevel):

    def __init__(self,parent: mainWindow):
        super().__init__(parent.root)

        self.parent = parent
        self.title("借阅图书")
        self.geometry("600x250")
        
        self.transient(parent.root)

        frame = ttk.Frame(self,padding = "10")
        frame.pack(fill = tk.BOTH,expand = True)
        frame.columnconfigure(1,weight = 1)

        # 表单项
        ttk.Label(frame,text = "ID:").grid(row = 0,column = 0,padx =  5,pady = 8,sticky = "w")
        self.id_entry = ttk.Entry(frame)
        self.id_entry.grid(row = 0,column = 1,padx = 5,pady = 8,sticky = "ew")

        ttk.Label(frame,text = "借阅人姓名:").grid(row = 1,column = 0,padx = 5,pady = 8,sticky = "w")
        self.name_entry = ttk.Entry(frame)
        self.name_entry.grid(row = 1,column = 1,padx = 5,pady = 8,sticky = "ew")

        btn_frame = tk.Frame(frame)
        btn_frame.grid(row = 2,column = 0,columnspan = 2,pady = 20)

        self.rend_button = ttk.Button(btn_frame,text = "借阅",command = self.onRendBook)
        self.rend_button.pack(side = tk.LEFT,padx = 10)
        ttk.Button(btn_frame,text = "取消",command = self.destroy).pack(side = tk.LEFT,padx = 10)



    def onRendBook(self):

        try:
            id_ = int(self.id_entry.get())
            name_ = self.name_entry.get()
        except (ValueError):
            messagebox.showerror("错误", "ID必须是整数！",parent=self)
            return 
    
        if not all([id_,name_]):
            messagebox.showerror("错误", "请填写完整借阅人姓名和书本ID！",parent=self)
            return 
        
        success = self.parent.library.rentBook(id_,name_)
        if success == False:
            if self.parent.library.queryBookByID(id_) == None:
                messagebox.showerror("错误","输入ID错误(无此ID的书)！",parent = self)
                return 
            messagebox.showinfo("提示", "此书已经被其他人借走。",parent=self)
            return 
        
        messagebox.showinfo("提示",f"用户 {name_} 借阅《{self.parent.library.queryBookByID(id_).name_}》成功！")
        self.parent.loadBooksToTreeView()
        self.destroy()


        return 

class returnWindow(tk.Toplevel):


    def __init__(self,parent: mainWindow):

        super().__init__(parent.root)
        self.parent = parent
        self.title("归还图书")
        self.geometry("600x300")
        self.transient(parent.root)
        
        frame = ttk.Frame(self)
        frame.pack(fill = tk.BOTH,expand = True)
        frame.columnconfigure(1,weight = 1)

        # 表单项
        ttk.Label(frame,text = "图书ID:").grid(row = 0,column = 0,padx = 5,pady = 8,sticky = "w")
        self.id_entry = ttk.Entry(frame)
        self.id_entry.grid(row = 0,column = 1,padx = 5,pady = 8,sticky = "ew")

        ttk.Label(frame,text = "借阅人姓名:").grid(row = 1,column = 0,padx = 5,pady = 8,sticky = "w")
        self.name_entry = ttk.Entry(frame)
        self.name_entry.grid(row = 1,column = 1,padx = 5,pady = 8,sticky = "ew")

        btn_frame = tk.Frame(frame)
        btn_frame.grid(row = 2,column = 0,columnspan = 2,pady = 20)

        self.return_button = ttk.Button(btn_frame,text = "归还",command = self.onReturnBook)
        self.return_button.pack(side = tk.LEFT,padx = 10)
        ttk.Button(btn_frame,text = "取消",command = self.destroy).pack(side = tk.LEFT,padx = 10)
        return 
    
    def onReturnBook(self):
        
        try:
            id_ = int(self.id_entry.get())
            name_ = self.name_entry.get()
        except (TypeError):
            messagebox.showerror("错误","输入图书ID必须是数字！",parent = self)
            return 

        if not all([id_,name_]):
            messagebox.showerror("错误","请输入ID和借阅人姓名！",parent = self)
            return 

        success = self.parent.library.returnBook(id_,name_)

        if success == False:
            messagebox.showerror("错误","输入图书ID错误或者输入借阅人姓名错误！",parent = self)
            return 
        
        messagebox.showinfo("提示",f"用户:{name_}归还图书成功。",parent = self)
        self.parent.loadBooksToTreeView()
        self.destroy()

        return 

